#pragma once

#include "XiInclude.hpp"

XI_NAMESPACE_BEGIN

#define TOKEN		0
#define SYMBOL		1
#define OPERATOR	2
#define KEYWORD		3
#define NODE		4

#define TUPLE_SIZE			3
#define TUPLE_KIND(elem)	BOOST_PP_TUPLE_ELEM(TUPLE_SIZE, 0, elem)
#define TUPLE_NAME(elem)	BOOST_PP_TUPLE_ELEM(TUPLE_SIZE, 1, elem)
#define TUPLE_DESC(elem)	BOOST_PP_CAT(L, BOOST_PP_TUPLE_ELEM(TUPLE_SIZE, 2, elem))
#define TUPLE_DESC_OR_NAME(elem) \
	BOOST_PP_IF( \
		BOOST_PP_EQUAL(TUPLE_KIND(elem), NODE), \
		BOOST_PP_WSTRINGIZE(BOOST_PP_CAT(BOOST_PP_CAT(<, TUPLE_NAME(elem)), >)), \
		TUPLE_DESC(elem) \
	)

#define TOKENKINDS \
	((TOKEN, FLOAT_LITERAL, "float literal")) \
	((TOKEN, HEX_LITERAL, "integer literal")) \
	((TOKEN, IDENTIFIER, "identifier")) \
	((TOKEN, INTEGER_LITERAL, "integer literal")) \
	((TOKEN, STRING_LITERAL, "string literal")) \
	((SYMBOL, AMPER, "&")) \
	((SYMBOL, ASTER, "*")) \
	((SYMBOL, CARET, "^")) \
	((SYMBOL, COLON, ":")) \
	((SYMBOL, COMMA, ",")) \
	((SYMBOL, DOT, ".")) \
	((SYMBOL, EQUAL, "=")) \
	((SYMBOL, EXCLAM, "!")) \
	((SYMBOL, GT, ">")) \
	((SYMBOL, LBRACK, "[")) \
	((SYMBOL, LCURLY, "{")) \
	((SYMBOL, LT, "<")) \
	((SYMBOL, LPAREN, "(")) \
	((SYMBOL, MINUS, "-")) \
	((SYMBOL, PERCENT, "%")) \
	((SYMBOL, PLUS, "+")) \
	((SYMBOL, RBRACK, "]")) \
	((SYMBOL, RCURLY, "}")) \
	((SYMBOL, RPAREN, ")")) \
	((SYMBOL, SEMICOLON, ";")) \
	((SYMBOL, SLASH, "/")) \
	((SYMBOL, TILDE, "~")) \
	((SYMBOL, VERTBAR, "|")) \
	((OPERATOR, OP_DEC, "--")) \
	((OPERATOR, OP_EQ, "==")) \
	((OPERATOR, OP_GE, ">=")) \
	((OPERATOR, OP_INC, "++")) \
	((OPERATOR, OP_LAND, "&&")) \
	((OPERATOR, OP_LE, "<=")) \
	((OPERATOR, OP_LOR, "||")) \
	((OPERATOR, OP_NE, "!=")) \
	((OPERATOR, OP_SHL, "<<")) \
	((OPERATOR, OP_SHR, ">>")) \
	((KEYWORD, KW_BASE, "base")) \
	((KEYWORD, KW_BREAK, "break")) \
	((KEYWORD, KW_CLASS, "class")) \
	((KEYWORD, KW_CONSTRUCTOR, "constructor")) \
	((KEYWORD, KW_CONTINUE, "continue")) \
	((KEYWORD, KW_DO, "do")) \
	((KEYWORD, KW_ELSE, "else")) \
	((KEYWORD, KW_FALSE, "false")) \
	((KEYWORD, KW_FOR, "for")) \
	((KEYWORD, KW_FUNCTION, "function")) \
	((KEYWORD, KW_IF, "if")) \
	((KEYWORD, KW_NULL, "null")) \
	((KEYWORD, KW_RETURN, "return")) \
	((KEYWORD, KW_SELF, "self")) \
	((KEYWORD, KW_TRUE, "true")) \
	((KEYWORD, KW_VAR, "var")) \
	((KEYWORD, KW_WHILE, "while")) \
	((NODE, D_BLOCK, _)) \
	((NODE, D_BREAK, _)) \
	((NODE, D_CLASS, _)) \
	((NODE, D_CONSTRUCTOR, _)) \
	((NODE, D_CONTINUE, _)) \
	((NODE, D_DOWHILE, _)) \
	((NODE, D_EXPRESSION_LIST, _)) \
	((NODE, D_FUNCTION, _)) \
	((NODE, D_FUNCTION_CALL, _)) \
	((NODE, D_IF, _)) \
	((NODE, D_MODULE, _)) \
	((NODE, D_PARAMETER_LIST, _)) \
	((NODE, D_RETURN, _)) \
	((NODE, D_SELECTOR, _)) \
	((NODE, D_VARIABLE, _)) \
	((NODE, D_VARIABLE_LIST, _)) \
	((NODE, D_WHILE, _))

/* token kinds */

#define MACRO0(r, data, i, elem) BOOST_PP_CAT(TK_, TUPLE_NAME(elem)),

enum XiTokenKind 
{
	TK_UNINITIALIZED = -1,
	TK_EOF = 0,
	
	BOOST_PP_SEQ_FOR_EACH_I(MACRO0, _, TOKENKINDS)
};

#undef MACRO0

/* token kind names */

#define MACRO0(r, data, i, elem) insert(std::make_pair(BOOST_PP_CAT(TK_, TUPLE_NAME(elem)), BOOST_PP_WSTRINGIZE(TUPLE_NAME(elem))));

struct XiTokenKindNameTable : std::map<XiTokenKind, XiString>
{
	static const XiTokenKindNameTable& Instance(void)
	{
		static XiTokenKindNameTable instance;
		return instance;
	}
	
	XiTokenKindNameTable(void)
	{
		BOOST_PP_SEQ_FOR_EACH_I(MACRO0, _, TOKENKINDS)
	}
};

#undef MACRO0

/* token kind descriptions */

#define MACRO0(r, data, i, elem) insert(std::make_pair(BOOST_PP_CAT(TK_, TUPLE_NAME(elem)), TUPLE_DESC_OR_NAME(elem)));

struct XiTokenKindDescTable : std::map<XiTokenKind, XiString>
{
	static const XiTokenKindDescTable& Instance(void)
	{
		static XiTokenKindDescTable instance;
		return instance;
	}
	
	XiTokenKindDescTable(void)
	{
		BOOST_PP_SEQ_FOR_EACH_I(MACRO0, _, TOKENKINDS)
	}
};

#undef MACRO0

/* keyword table */

#define MACRO0(r, data, i, elem) BOOST_PP_EXPR_IF( \
		BOOST_PP_EQUAL(TUPLE_KIND(elem), KEYWORD), \
		insert(std::make_pair(TUPLE_DESC(elem), BOOST_PP_CAT(TK_, TUPLE_NAME(elem)))); \
	)

struct XiKeywordTable : std::map<XiString, XiTokenKind>
{
	static const XiKeywordTable& Instance(void)
	{
		static XiKeywordTable instance;
		return instance;
	}
	
	XiKeywordTable(void)
	{
		BOOST_PP_SEQ_FOR_EACH_I(MACRO0, _, TOKENKINDS)
	}
};

#undef MACRO0

#undef TOKENKINDS

#undef TUPLE_SIZE
#undef TUPLE_KIND
#undef TUPLE_NAME
#undef TUPLE_DESC

#undef TOKEN
#undef SYMBOL
#undef OPERATOR
#undef KEYWORD
#undef NODE

XI_NAMESPACE_END